package com.docmgmt.mvp.ragflow;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * RAGFlow LLM查询客户端
 * 负责查询RAGFlow中配置的LLM模型列表
 *
 * 支持的API端点：
 * 1. GET /v1/llm/my_llms - 获取当前租户配置的LLM
 * 2. GET /v1/llm/list - 获取所有可用的LLM工厂
 */
@Slf4j
@Component
public class RAGFlowLLMClient {

    @Value("${ragflow.base-url}")
    private String apiUrl;

    @Autowired
    private RAGFlowAuthClient authClient;

    private final HttpClient httpClient;
    private final ObjectMapper objectMapper;

    public RAGFlowLLMClient() {
        this.httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();
        this.objectMapper = new ObjectMapper();
    }

    /**
     * 获取当前租户配置的LLM列表
     *
     * @return LLM列表
     * @throws Exception 如果查询失败
     */
    public List<LLMModel> getMyLLMs() throws Exception {
        return queryLLMs("/v1/llm/my_llms");
    }

    /**
     * 获取所有可用的LLM工厂列表
     *
     * @return LLM工厂列表
     * @throws Exception 如果查询失败
     */
    public List<LLMFactory> getFactoryList() throws Exception {
        String sessionToken = authClient.getSessionToken();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(apiUrl + "/v1/llm/list"))
                .header("Authorization", sessionToken)
                .GET()
                .timeout(Duration.ofSeconds(30))
                .build();

        log.debug("发送RAGFlow LLM工厂列表查询: GET {}/v1/llm/list", apiUrl);

        HttpResponse<String> response = executeRequestWithRetry(request);

        // 解析响应
        FactoryListResponse factoryListResponse = objectMapper.readValue(
                response.body(), FactoryListResponse.class);

        if (factoryListResponse.getCode() != 0) {
            log.error("查询LLM工厂列表失败: code={}, message={}",
                    factoryListResponse.getCode(), factoryListResponse.getMessage());
            throw new RuntimeException("查询LLM工厂列表失败: " + factoryListResponse.getMessage());
        }

        List<LLMFactory> factories = factoryListResponse.getData();
        log.info("成功查询LLM工厂列表: 共{}个工厂", factories.size());

        return factories;
    }

    /**
     * 通用LLM查询方法（带自动重试）
     *
     * @param endpoint API端点（如 /v1/llm/my_llms）
     * @return LLM列表
     * @throws Exception 如果查询失败
     */
    private List<LLMModel> queryLLMs(String endpoint) throws Exception {
        String sessionToken = authClient.getSessionToken();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(apiUrl + endpoint))
                .header("Authorization", sessionToken)
                .GET()
                .timeout(Duration.ofSeconds(30))
                .build();

        log.debug("发送RAGFlow LLM查询: GET {}{}", apiUrl, endpoint);

        HttpResponse<String> response = executeRequestWithRetry(request);

        // 解析响应
        LLMListResponse llmListResponse = objectMapper.readValue(
                response.body(), LLMListResponse.class);

        if (llmListResponse.getCode() != 0) {
            log.error("查询LLM列表失败: code={}, message={}",
                    llmListResponse.getCode(), llmListResponse.getMessage());
            throw new RuntimeException("查询LLM列表失败: " + llmListResponse.getMessage());
        }

        // 扁平化按工厂分组的数据
        List<LLMModel> models = new ArrayList<>();
        Map<String, FactoryInfo> factoryMap = llmListResponse.getData();

        if (factoryMap != null) {
            for (Map.Entry<String, FactoryInfo> entry : factoryMap.entrySet()) {
                String factory = entry.getKey();
                FactoryInfo factoryInfo = entry.getValue();

                if (factoryInfo.getLlm() != null) {
                    for (LLMModelRaw raw : factoryInfo.getLlm()) {
                        LLMModel model = new LLMModel();
                        model.setLlmFactory(factory);
                        model.setLlmName(raw.getName());
                        model.setModelType(raw.getType());

                        // 可选字段
                        if (raw.getApiBase() != null) {
                            model.setApiBase(raw.getApiBase());
                        }

                        models.add(model);
                    }
                }
            }
        }

        log.info("成功查询LLM列表: 共{}个工厂，{}个模型", factoryMap != null ? factoryMap.size() : 0, models.size());

        return models;
    }

    /**
     * 执行HTTP请求（带401自动重试）
     *
     * @param request HTTP请求
     * @return HTTP响应
     * @throws Exception 如果请求失败
     */
    private HttpResponse<String> executeRequestWithRetry(HttpRequest request) throws Exception {
        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

        // 如果收到401，说明令牌过期，刷新后重试一次
        if (response.statusCode() == 401) {
            log.warn("收到401响应，会话令牌可能已过期，尝试刷新令牌并重试");
            authClient.clearSessionToken();
            String newToken = authClient.refreshSessionToken();

            // 重新构建请求（使用新令牌）
            HttpRequest retryRequest = HttpRequest.newBuilder()
                    .uri(request.uri())
                    .header("Authorization", newToken)
                    .GET()
                    .timeout(Duration.ofSeconds(30))
                    .build();

            response = httpClient.send(retryRequest, HttpResponse.BodyHandlers.ofString());
        }

        if (response.statusCode() != 200) {
            log.error("RAGFlow请求失败: HTTP {}, 响应: {}", response.statusCode(), response.body());
            throw new RuntimeException("RAGFlow请求失败: HTTP " + response.statusCode() + ", " + response.body());
        }

        return response;
    }

    /**
     * 格式化LLM ID（model_name@factory格式）
     *
     * @param modelName 模型名称
     * @param factory   工厂名称
     * @return 格式化的LLM ID
     */
    public static String formatLLMId(String modelName, String factory) {
        if (factory == null || factory.isEmpty()) {
            return modelName;
        }
        return modelName + "@" + factory;
    }

    /**
     * 解析LLM ID（拆分model_name和factory）
     *
     * @param llmId LLM ID
     * @return [modelName, factory]数组
     */
    public static String[] parseLLMId(String llmId) {
        if (llmId == null || !llmId.contains("@")) {
            return new String[]{llmId, null};
        }
        int atIndex = llmId.lastIndexOf("@");
        return new String[]{
                llmId.substring(0, atIndex),
                llmId.substring(atIndex + 1)
        };
    }

    // ==================== 内部类：响应结构 ====================

    /**
     * LLM列表响应（按工厂分组）
     * RAGFlow返回格式：{"BAAI": {"llm": [...], "tags": "..."}, "SILICONFLOW": {...}}
     */
    @Data
    private static class LLMListResponse implements Serializable {
        private static final long serialVersionUID = 1L;
        
        private Integer code;
        private String message;
        private Map<String, FactoryInfo> data;  // key=工厂名, value=工厂信息
    }

    /**
     * 工厂信息（包含LLM列表和标签）
     */
    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    private static class FactoryInfo implements Serializable {
        private static final long serialVersionUID = 1L;
        
        private List<LLMModelRaw> llm;  // LLM列表
        private String tags;             // 工厂标签
    }

    /**
     * RAGFlow原始LLM模型数据（用于JSON反序列化）
     */
    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    private static class LLMModelRaw implements Serializable {
        private static final long serialVersionUID = 1L;
        
        private String name;

        @JsonProperty("type")
        private String type;

        @JsonProperty("used_token")
        private Integer usedToken;

        @JsonProperty("api_base")
        private String apiBase;

        @JsonProperty("max_tokens")
        private Integer maxTokens;
    }

    /**
     * LLM工厂列表响应
     */
    @Data
    private static class FactoryListResponse implements Serializable {
        private static final long serialVersionUID = 1L;
        
        private Integer code;
        private String message;
        private List<LLMFactory> data;
    }

    /**
     * LLM模型信息
     */
    @Data
    public static class LLMModel implements Serializable {
        private static final long serialVersionUID = 1L;
        
        /**
         * 模型名称（如：qwen-plus, deepseek-chat）
         */
        private String llmName;

        /**
         * 工厂名称（如：Tongyi-Qianwen, SILICONFLOW）
         */
        private String llmFactory;

        /**
         * 模型类型（chat, embedding, rerank, image2text等）
         */
        private String modelType;

        /**
         * API密钥（前端不应显示）
         */
        private String apiKey;

        /**
         * API基础URL
         */
        private String apiBase;

        /**
         * 创建时间
         */
        private String createTime;

        /**
         * 更新时间
         */
        private String updateTime;

        /**
         * 获取完整的LLM ID（model_name@factory格式）
         */
        public String getFullLLMId() {
            return formatLLMId(llmName, llmFactory);
        }

        /**
         * 获取显示名称
         */
        public String getDisplayName() {
            return llmFactory + " - " + llmName;
        }
    }

    /**
     * LLM工厂信息
     */
    @Data
    public static class LLMFactory implements Serializable {
        private static final long serialVersionUID = 1L;
        
        /**
         * 工厂名称（如：OpenAI, Tongyi-Qianwen）
         */
        private String name;

        /**
         * 工厂显示名称
         */
        private String displayName;

        /**
         * 支持的模型类型列表
         */
        private List<String> supportedTypes;

        /**
         * 工厂描述
         */
        private String description;

        /**
         * 是否需要API密钥
         */
        private Boolean requiresApiKey;
    }
}
